package com.liz.lizrpccore.core.providers.netty;

import com.liz.lizrpccore.core.providers.AbstractLizRpc;
import com.liz.lizrpccore.core.providers.LizPrcProvider;
import com.liz.lizrpccore.properties.LizRpcProperties;
import com.liz.lizrpccore.templates.excute.ExecutorServiceComponent;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * @author liangGongWei
 * @description
 * @create 2021-09-22 15:00
 **/

public class LizRpcNettyProvider extends AbstractLizRpc implements LizPrcProvider {
    private static Boolean nettyServerStartFlag = false;

    private static Logger log = LoggerFactory.getLogger(LizRpcNettyProvider.class);

    @Override
    public void providerToRemote(List<String> classNameList, LizRpcProperties lizRpcProperties) {
        if (!nettyServerStartFlag) {
            nettyServerStartFlag = true;
            ExecutorServiceComponent.getDefaultExecutorService().execute(() -> {
                providerToRemote(lizRpcProperties);
            });

        }
    }

    public static void providerToRemote(LizRpcProperties lizRpcProperties) {
        EventLoopGroup master = new NioEventLoopGroup();
        EventLoopGroup slave = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(master, slave)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            ChannelPipeline pipeline = socketChannel.pipeline();
                            pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                            pipeline.addLast(new LengthFieldPrepender(4));
                            pipeline.addLast("encoder", new ObjectEncoder());
                            pipeline.addLast("decoder", new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));
                            pipeline.addLast(new MyReflectInvokingHandler());
                        }
                    });
            ChannelFuture future = serverBootstrap.bind(Integer.parseInt(lizRpcProperties.getProtocolPort())).sync();
            log.info("RPC registry start listen at :{}",lizRpcProperties.getProtocolPort());
            future.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            master.shutdownGracefully();
            slave.shutdownGracefully();
        }
    }
}
